package org.carabiner.infinitest;

import java.util.HashSet;
import java.util.Set;

import junit.framework.AssertionFailedError;

import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;

class TestEventAdapter extends RunListener
{
  private final TestRunnerEventSupport eventSupport;
  private Set<Description> testMethodsRun;

  public TestEventAdapter(TestRunnerEventSupport parentEventSupport)
  {
    eventSupport = parentEventSupport;
    testMethodsRun = new HashSet<Description>();
  }
  
  @Override
  public void testStarted(Description description) throws Exception
  {
    testMethodsRun.add(description);
  }
  
  @Override
  public void testRunFinished(Result result) throws Exception
  {
    // HACK Refactor - This method needs some serious refactoring...but I've tried three times already and haven't made it cleaner.
    HashSet<Description> successfulTestMethods = new HashSet<Description>();
    Set<String> failingTestCases = new HashSet<String>();
    successfulTestMethods.addAll(testMethodsRun);
    for(Failure failure: result.getFailures())
    {
      Description testDescription = failure.getDescription();
      String testCaseName = getTestCaseName(testDescription);
      if (failure.getException() instanceof AssertionFailedError || failure.getException() instanceof AssertionError)
        eventSupport.fireTestFailed(testCaseName, failure.getMessage(), failure.getException(), getMethodName(testDescription));
      else
        eventSupport.fireTestError(testCaseName, failure.getMessage(), failure.getException(), getMethodName(testDescription));
      successfulTestMethods.remove(testDescription);
      failingTestCases.add(testCaseName);
    }
    
    for (Description sucessfulTest : successfulTestMethods)
    {
      String testCaseName = getTestCaseName(sucessfulTest);
      eventSupport.fireTestMethodSucceeded(testCaseName, getMethodName(sucessfulTest));
      if (!failingTestCases.contains(testCaseName))
      {
        eventSupport.fireTestCaseSucceeded(testCaseName);
        failingTestCases.add(testCaseName);
      }
    }
  }

  private static String getTestCaseName(Description description)
  {
    return description.getDisplayName().split("\\(|\\)")[1];
  }

  private String getMethodName(Description description)
  {
    return description.getDisplayName().split("\\(|\\)")[0];
  }
}
